/// <reference path="../brandIE.controls.js" />
/// <reference path="brandIE.controls.store.js" />
/**
create grid include header,paging,sort
last modify by
*/
(function ($) {

    var ns_grid = nsbase.controls.grid = Grid;
    ns_grid.gridEditor = GridEditor;

    var ns_store = nsbase.controls.store;
    //ns_grid.gridPaggingBar = GridPaggingBar;

    //表格控件
    function Grid(opt) {
        var _eventObserver = new nsbase.controls.eventObserver(_self);
        var resources = Grid.resources.getResourcePackage(),
        formatters = Grid.cellFormatters;

        //#region attribute
        var ROW_DATA_KEY = 'dataRow',
        CLS_INPUT_CHECKBOX = 'input:checkbox',
        CLS_GRID_TABLE = 'grid-table',
        CLS_GRID_ROW = 'grid-row',
        CLS_GRID_GROUP_ROW = 'grid-group-row',
        CLS_COLUMN_LOOKUP = 'lookup',
        CLS_COLUMN_EXPAND = 'expand',
        CLS_COLUMN_HIDEN = 'hide',
        CLS_BODY_EDITER = 'grid-body-cell-editor',
        CLS_HEADER_ROW = 'grid-header-row',
        CLS_HEADER_TITLE = 'header-title',
        CLS_HEADER_SUBTITLE = 'header-subtitle',
        CLS_HEADER_INNER = 'header-inner',
        CLS_HEADER_EDITER = 'header-editor',
        CLS_HEADER_SELECTABLE = 'selectable',
        CLS_HEADER_SELECTED = 'selected',
        CLS_HEADER_SORTABLE = 'sortable',
        CLS_EDITABLE = 'editable',
        CLS_DISABLED = 'disabled',
        CLS_CHECKBOX = 'gwt-CheckBox',
        CLS_HEADER_EDIT_BTN = 'header-edit-btn',
        CLS_HEADER_EDIT_FIELD = 'grid-edit-filed',
        CLS_HEADER_EDIT_FIELD_WRAP = 'grid-edit-filed-wrap',
        CLS_MULTIPLE_EDIT = 'editing',
        CLS_CELL_TEXT = 'cell-text',
        CLS_CELL_INNER = 'cell-inner',
        CLS_HOVER = 'hover',
        CLS_VALIDATE = 'validate',
        CLS_GRID_CELL = 'grid-cell',
        CLS_GRID_CELL_TIP = 'cell-tip',
        ATTR_COLUMN_NAME = 'data-column-name',
        ATTR_COINDEX = 'colindex',
        DEFINITION_COLUMN = 'columnDef',
        SORT_ASC = 'ASC',
        SORT_DESC = 'DESC',
        CLS_SORT_ASC = 'asc',
        CLS_SORT_DESC = 'desc',
        CLS_SELECTED = 'selected',
        TIP_SAVE = resources.Save,
        TIP_EDIT = resources.ButtonEdit,
        TEXT_SELECT_DEFAULT = resources.General_Select;

        var gridId, renderTo, gridEl, headerEl, gridViewEl, headerRowEl, gridBodyEl, rowsBodyEl, tableEl, footerEl, tbar, bbar, masked, saveMask, header,
        _cachedDataFieldMapping, _defaultSelectedColumn, _isLocalData = false;

        //#endregion

        var _self = this;

        var RowSelectableEnum = {
            None: 'none',
            Single: 'single',
            Multiple: 'multiple'
        };

        var _defaultConfig = {
            renderTo: '',
            rowNumber:false,
            rowSelectable: RowSelectableEnum.Single,
            width: null,
            height: 500,
            autoHeight: true,
            minHeight: 200, // px
            columns: [],
            loadMask: false,
            paggingBar: null,   //paggingBar: {pageIndex: 1, pageSize: 20}
            expandChildren: null,//expandChildren: { dataIndex: null, childrenIndex: null, allowGroupCheck: false, formater: null }
            footer: null,       //footer: { info: '', url: '', action: ''}
            store: null         // store:{remote: true, url: "", methodType: "POST", data: null, sortField: "", sortDirect: "ASC" }

        };

        var _defaultColumnConfig = {
            groupIndex: null,
            title: null,
            hidden:false,
            enumTypeName: null,
            editor: null,   // GridEditor()
            formater: null, // function(colDef,value, record){}
            isCurrency: false,
            isPercentage: false,
            type: 'text',
            width: 100,
            align:"center",
            sortable: false,
            selectable:false,
            editable: false,
            headereditable: false,
            exportable: true,
            subtitle: null
        }


        var _config, _container, _gridId, _store;

        //#region Column Definition template don't delete
        //var columnDefinition = {
        //    groupIndex: null,
        //    title: null,
        //    enumTypeName: null,
        //    chartTypes: [], // 一个列上可以配置多个chartType值
        //    selected: false, // 只能有一个 对应isDefaultChart
        //    editor: null,
        //    formater: null,
        //    isCurrency: null,
        //    isPercentage: null,
        //    type: 'text',
        //    width: 100,
        //    sortable: true,
        //    editable: false,
        //    exportable:true,
        //    subtitle: null,
        //    headereditable: null,
        //    showTip: false, // row title
        //    tooltip: null   //tooltip: { key: 'Phoenix_Status_AdGroup', cssClass: "imgTipBlack" }
        //};
        //#endregion




        _self.gridId = _gridId;
        _self.gridConfig = _config;

        _self.on = _eventObserver.on;
        _self.un = _eventObserver.un;
        _self.unAll = _eventObserver.unAll;

        function _init() {
            _config = $.extend(true, {}, _defaultConfig, opt);
            if (!_config.renderTo) {
                throw 'please provide the render of the grid' + _config.renderTo;
            }
            _container = $('#' + _config.renderTo);
            if (_container.length === 0) {
                throw 'please check the wrapper of the grid' + _config.renderTo;
            } else {
                _container.empty();
            }
            _gridId = _config.renderTo + 'Grid';
            initGrid(_gridId);

        };
        _init();

        //#region Public methods
        /*
            函数功能：在表格中显示数据
            参数： @data 为一个数组
            返回值：void
            */
        _self.showData = showData;
        /*
        函数功能：获取选中的数据，如果选中多行，仅返回第一行
        参数： 无
        返回值：一个对象
        */
        _self.getSelected = function () {

            var row = $('.' + CLS_GRID_ROW + '.' + CLS_SELECTED, gridEl).first();
            if (row.length) {
                return row.data(ROW_DATA_KEY);
            }
        };

        /*
        函数功能：获取选中的数据，如果选中多行，则返回所有行
        参数： 无
        返回值：Array
        */
        _self.getSelections = function () {
            var result = [];
            $('.' + CLS_GRID_ROW + '.' + CLS_SELECTED, gridEl).
            each(function (index, element) {
                result.push($(element).data(ROW_DATA_KEY));
            });
            return result;
        };

        /*
        函数功能：获取选中列，为配置中Columns中的元素
        参数： 无
        返回值：列对象 
        */
        _self.getSelectedColumn = function () {
            var selectedColumnEl = $('th.' + CLS_HEADER_SELECTED, headerEl);
            var def = selectedColumnEl.data(DEFINITION_COLUMN);
            if (def) {
                return def;
            }
        };

        /*
        函数功能：获取选中列对应的字段名，为配置中Columns中元素的 dataIndex属性
        参数： 无
        返回值：字符串，列的属性名
        */
        _self.getSelectedColumnField = function () {
            var selectedColumn = _self.getSelectedColumn();
            if (selectedColumn)
                return selectedColumn.dataIndex;
        };

        /*
        函数功能：获取选中列对应的字段名，为配置中Columns中元素的 dataIndex属性
        参数： 无
        返回值：字符串，列的属性名
        */
        _self.getSelectedChartType = function () {
            var selectedColumn = _self.getSelectedColumn();
            if (selectedColumn)
                return selectedColumn.chartType;
        };

        /*
        函数功能：获取选中列对应的字段索引，为配置中Columns中元素的索引
        参数： 无
        返回值：数值，选中的列的索引
        */
        _self.getSelectedColumnIndex = function () {
            var field = _self.getSelectedColumnField();
            return getColumnIndex(field);
        };

        /*
        函数功能：根据索引，设置选中列。展开列不在此索引内
        参数： 索引
        返回值：无
        */
        _self.setSelectColumnByIndex = function (index) {
            var columnEl = $('th.grid-column-' + index, headerEl);
            if (columnEl && columnEl.hasClass(CLS_HEADER_SELECTABLE)) {
                selectColumn(columnEl);
            }
        };

        /*
        函数功能：根据字段，设置选中列。
        参数： 字段名称
        返回值：无
        */
        _self.setSelectColumnByField = function (field) {
            var columnEl = getColumn(field);
            if (columnEl && columnEl.hasClass(CLS_HEADER_SELECTABLE)) {
                selectColumn(columnEl);
            }
        };

        /*
        函数功能：根据配置列，设置选中列。
        参数： 列的配置选项
        返回值：无
        */
        _self.setSelectColumn = function (column) {
            if (column) {
                _self.setSelectColumnByField(column.dataIndex);
            }
        };

        /*
        函数功能：获取 Store ，存取数据的对象配置
        参数： 无
        返回值：Store
        */
        _self.getStoreConfig = function () {
            return _config.store;
        };

        /*
        函数功能：获取 Store ，存取数据的对象配置
        参数： 无
        返回值：Store
        */
        _self.getStore = function () {
            ///<returns type="Object">存取数据的对象配置</returns>
            return _store;
        };
        /*
        函数功能：更新标题，子标题
        参数： field: 字段名； title:标题；subtitle：子标题
        返回值：无
        */
        _self.updateTitle = function (field, title, subtitle) {
            var columnEl = getColumn(field);

            columnEl.find('.' + CLS_HEADER_TITLE).text(title);
            columnEl.find('.' + CLS_HEADER_SUBTITLE).text(subtitle);

        }

        /*
        函数功能：子标题
        参数： field: 字段名； title:标题；subtitle：子标题
        返回值：无
        */
        _self.updateSubTitle = function (field, subtitle) {
            //index = getColumnIndex(field),
            var columnEl = getColumn(field);
            columnEl.find('.' + CLS_HEADER_SUBTITLE).text(subtitle);
        };

        /*
       函数功能：获取需要导出列的列定义
       参数： 无
       返回值：可导出列的列定义
       */
        _self.getExportColumns = function () {
            var exportColumns = [];
            $(_config.columns).each(function (i, column) {
                if (column.exportable) {
                    var columnDefin = {
                        name: column.dataIndex,
                        displayName: column.title,
                        isCurrency: column.isCurrency,
                        isPercentage: column.isPercentage,
                        enumTypeName: column.enumTypeName
                    };
                    exportColumns.push(columnDefin);
                }
            });

            return exportColumns;
        };

        _self.refresh = function () {
                if(_store){
                    _store.reLoad();
                }
        }
        _self.updateRows = function (records, dataItems) {
            updateRowsData(records, dataItems);
        }

        _self.destroy = function () {
            if (tbar) {
                tbar.destroy();
            }
            if (bbar) {
                bbar.destroy();
            }
            removeStoreEvents();
            if (saveMask) {
                saveMask.destroy();
            }
            gridEl.remove();
            removeGridEvents();
        };

        _self.clearSelections = function () {
            setHeaderSelected(false);
            clearRrowsSelected();
        };

        _self.setMultipleEdit = function (enable) {
            setGridMultipleEdit(enable);
        };

        _self.isMultipleEditStatus = function () {
            return isMultipleEditStatus();
        }

        _self.autoResize = function () {
            setHeaderTableWidth();
            if (_config.autoHeight) {
                setBodyTableHeight();
            }
        }

        _self.setSelections = function (field, values) {
            var rows = gridEl.find('.' + CLS_GRID_ROW);
            $(rows).each(function (index, element) {
                var obj = $(element).data(ROW_DATA_KEY);
                if ($.inArray(obj[field], values) >= 0) {
                    setSelectRow($(element), true);
                }
            });
        }

        _self.setRowUnselected = function (record) {
            setRowUnselected(record);
        }

        _self.setRowUnEditable = function (record, field, callBack) {
            setRowUnEditable(record, field, callBack);
        }

        _self.setRowEditable = function (record, field, callBack) {
            setEditable(record, field, callBack);
        }

        _self.setRowDisable = function (record) {
            setRowDisable(record);
        }

        //设置行灰化（不可编辑，但可选，灰色显示）
        _self.setRowGray = function (record) {
            setRowGray(record);
        }

        _self.deleteSelectedRows = function () {
            deleteSelectedRows();
        }

        _self.renderCell = function (record, dataItems) {
            renderCell(record, dataItems);
        }

        //#endregion

        //#region FireEvents 

        function onDataReceivedAction(data) {
            _eventObserver.fireEvent(Grid.setting.eventEnums.dataReceived, [data]);
        }

        function onDataError(error) {
            _eventObserver.fireEvent(Grid.setting.eventEnums.dataError, error);
        }
        function onAfterShow() {
            _eventObserver.fireEvent(Grid.setting.eventEnums.afterShow);
        };

        function onRowClick(params) {
            _eventObserver.fireEvent(Grid.setting.eventEnums.rowClick, params);
        };

        function onCellClick(params) {
            _eventObserver.fireEvent(Grid.setting.eventEnums.cellClick, params);
        };

        function onColumnSelectChanged(params) {
            _eventObserver.fireEvent(Grid.setting.eventEnums.columnSelectChanged, params);
        };

        function onRowSelectChanged() {
            _eventObserver.fireEvent(Grid.setting.eventEnums.rowSelectChanged);
        };

        //#endregion

        //#region moitor Store events

        //监听Store事件
        function monitorStoreEvents() {
            if (_store) {
                var storeEvents = ns_store.setting.eventEnums;
                _store.on(storeEvents.beforeLoad, beforeLoadAction);
                _store.on(storeEvents.dataReceived, dataReceivedAction);
                _store.on(storeEvents.dataBind, dataBindAction);
                _store.on(storeEvents.dataError, dataErrorAction);
            }
        }

        // 取消监听 Store 事件
        function removeStoreEvents() {
            if (_store) {
                _store.unAll();
            }
        }

        function beforeLoadAction() {
            if (_config.loadMask) {
                _container.mask();
                masked = true;
            }
        }

        function dataReceivedAction(data) {
            // fire grid dataReceived action
            onDataReceivedAction(data);
        }

        function dataBindAction(data) {
            if (!data) {
                data = _store.getResults();
            }
            showData(data);
            onAfterShow();
            afterShowAction();
        }

        function dataErrorAction(error) {
            // fire grid dataError action
            onDataError(error);
        }

        //#endregion


        //#region moitor grid events

        function removeGridEvents() {
            _self.unAll();
        }

        //#endregion


        //初始化表格
        function initGrid(gridId) {
            var gridTemp = ['<div id="', gridId, '" class="grid-panel"><div class="grid-view"><div class="grid-header"></div><div class="grid-body"><table  cellspacing="0" cellpadding="0" class="', CLS_GRID_TABLE, 
            '"><tbody><tfoot></tfoot></tbody></table></div></div><div id="', gridId ,'tbar" class="grid-pagging-bar" style="display: none;"></div></div>'].join('');
            gridEl = $(gridTemp).appendTo(_container);
            gridBodyEl = gridEl.find('.grid-body');
            tableEl = gridBodyEl.find('.' + CLS_GRID_TABLE);
            gridViewEl = gridEl.find('.grid-view');
            footerEl = tableEl.children('tfoot');
            rowsBodyEl = tableEl.children('tbody');
            initColumns();
            createHeader();

            if (_config.width) {
                gridEl.width(_config.width);
            }
            var height = _config.height ? _config.height : _config.minHeight;
            var headerHeight = headerEl.height();
            gridBodyEl.height(height - headerHeight);

            initEvent();

            if (_config.store) {
                _store = createStore();
                monitorStoreEvents();
            }

            if (_config.paggingBar) {
                tbar = createPageBar();
            } else if (_store) {
                _store.load();
            }
        }

        function createPageBar() {
            var barConfig = $.extend(true, {}, _config.paggingBar);
            barConfig.renderTo = _gridId + "tbar";
            barConfig.store = _store;
            $('.grid-pagging-bar', gridEl).show();

            var paggingBar = new GridPaggingBar(barConfig);
            if (!_store) {
                paggingBarEvents = ns_grid.paggingBar.setting.eventEnums;
                paggingBar.on(paggingBarEvents.localDataBind, localDataBindAction);
            }
            return paggingBar;
        }

        function localDataBindAction(data) {
            showData(data);
            onAfterShow();
            afterShowAction();
        }

        function createStore() {
            var storeConfig = $.extend(true, {}, _config.store);
            if (_config.paggingBar) {
                storeConfig.pageRemote = _config.paggingBar.remote || false;
                storeConfig.pageIndex = _config.paggingBar.pageIndex;
                storeConfig.pageSize = _config.paggingBar.pageSize;
            }
            return new nsbase.controls.store(storeConfig);
        }

        //#region private func

        function showData(data) {
            clearData();
            if (!data || !data.length) {
                createEmptyRow();
            } else {
                if (tbar && !_store && !_isLocalData) {
                    _isLocalData = true;
                    tbar.setResults(data);
                    return;
                }
                $(data).each(function (index, element) {
                    if (_config.expandChildren) {
                        var groupName = element[_config.expandChildren.dataIndex] || '',
                        cDataIndex = _config.expandChildren.childrenIndex || '';
                        createGroupRow(index, groupName, element);
                        createGroupChildrenRows(index, cDataIndex, element);
                    } else {
                        createRow(index + 1, element);
                    }
                });
                if (_config.footer) {
                    createFooter();
                }
            }
            setHeaderTableWidth();
            if (_config.autoHeight) {
                setBodyTableHeight();
            }
        }

        //清除所有显示的数据
        function clearData() {
            clearRrowsSelected();
            $('tr.' + CLS_GRID_ROW, gridEl).remove();
            $('tr.row-empty', gridEl).remove();
        };

        //清除所有选择
        function clearRrowsSelected() {
            setSelectRow($('.' + CLS_GRID_ROW, gridEl), false);
        };

        function createEmptyRow() {
            var colspan = getAllColumnsCount();
            var emptyTemplate = ['<tr class="row-empty"><td colSpan = "', colspan, '">',
            //'<span class="empty-warning">', resources.ShortError_NoData,'</span>',
            '</td></tr>'].join(''),
            rowEl = $(emptyTemplate).appendTo(rowsBodyEl);
            return rowEl;
        };

        function getAllColumnsCount() {
            return $('th', headerRowEl).length;
        };

        function renderCell(record, dataItems) {
            var rows = gridEl.find('.' + CLS_GRID_ROW);
            $(rows).each(function (index, element) {
                var obj = $(element).data(ROW_DATA_KEY);
                if (obj == record) {
                    // zjk localstatus
                    $.each(dataItems, function (i, item) {
                        var field = item.dataIndex,
                        value = item.value;
                        record[_cachedDataFieldMapping[field.toLowerCase()]] = value; // 更新store值
                        var cell = $(element).find('.grid-body-td-' + field).find('.' + CLS_CELL_TEXT),
                        colDef = getCoumnDefinition(field);
                        var editValue = colDef ? (colDef.formater ? colDef.formater(colDef,value, record) : value) : formatters.generalFormatter(value);
                        cell.html(editValue);
                        if (colDef && colDef.showTip) {
                            cell.attr('title', value);
                        }
                    });
                }
            });
        }

        function getColumnIndex(field) {
            var index = 0;
            $(_config.columns).each(function (i, element) {
                if (element.dataIndex == field) {
                    index = i;
                    return false;
                }
            });
            return index;
        }

        function getColumn(field) {
            return headerEl.find('.grid-header-column-' + field);
        }

        function getCoumnDefinition(field) {
            return getColumn(field).data(DEFINITION_COLUMN);
        }

        function initEvent() {

            //initHeaderEvent();
            initBodyEvent();

            //公用的，lookup 的hover
            $('.' + CLS_COLUMN_LOOKUP, _container).on('mouseover', function () {
                var target = "grid-column-" + $(this).attr("colindex");
                $('.' + CLS_COLUMN_LOOKUP + "." + target, _container).addClass(CLS_HOVER);
            }).on('mouseout', function () {
                var target = "grid-column-" + $(this).attr("colindex");
                $('.' + CLS_COLUMN_LOOKUP + "." + target, _container).removeClass(CLS_HOVER);
            });
        }

        function beforeLoadAction() {
            if (_config.loadMask) {
                _container.mask();
                masked = true;
            }
        }

        function afterShowAction() {
            if (masked == true) {
                _container.unmask();
                masked = false;
            }
        }

        function loadAction(mystore) {
            _self.showData(mystore.getResult());
            if (masked == true) {
                _container.unmask();
                masked = false;
            }
        }

        function exceptionAction(store, msg) {
            if (masked == true) {
                _container.unmask();
                masked = false;
            }

            if (saveMask) {
                saveMask.hide();
            }
            if (msg) {
                alert(msg);
            }
        }

        function sortAction() {
            if (_config.store) {
                //todo: [OldReportTracking]
                var field = _config.store.sortInfo.field,
                direction = _config.store.sortInfo.direction;
                sortColumn(field, direction);
            }
        }

        function beforeSaveAction() {
            if (saveMask) {
                saveMask.show();
            }
        }

        function afterSaveAction() {
            if (saveMask) {
                saveMask.hide();
            }
        }

        function dataChangedAction(store, records, dataItems) {
            updateRowsData(records, dataItems);
        }

        function dataAppendedAction(store, records) {
            var startIndex = tableEl.find('tr.' + CLS_GRID_ROW).size();
            $(records).each(function (index, element) {
                createRow(index + startIndex, element);
            });
        }

        // dataItems{ key:"dbField", value:"value",dataIndex:"gridDataIndex"}
        function updateRowsData(records, dataItems) {
            var rows = gridEl.find('.' + CLS_GRID_ROW);
            $(rows).each(function (index, element) {
                var obj = $(element).data(ROW_DATA_KEY);
                $.each(records, function (i, record) {
                    if (obj == record) {
                        $.each(dataItems, function (j, item) {
                            var field = (item.dataIndex || item.key),
                            value = item.value;
                            record[_cachedDataFieldMapping[field.toLowerCase()]] = value; // 修改Store的值
                        });

                        refreshRow(record, element);
                    }
                });
            });
        }

        function refreshRow(record, element) {
            for (var i = 0; i < _config.columns.length; i++) {
                var column = _config.columns[i];
                refreshCell(column, record, element);
            }
        }

        function refreshCell(column, record, element) {
            if (column.lookup) {
                $.each(column.lookup.columns, function (i, lookupColumn) {
                    refreshCell(lookupColumn, record, element);
                });
            }
            if (column.dataIndex) {
                var cell = $(element).find('.grid-body-td-' + column.dataIndex).find('.' + CLS_CELL_TEXT),
                value = record[_cachedDataFieldMapping[column.dataIndex.toLowerCase()]],
                colDef = getCoumnDefinition(column.dataIndex),
                editValue = colDef ? (colDef.formater ? colDef.formater(value, record) : value) : formatters.generalFormatter(value);
                cell.html(editValue);

                if (colDef && colDef.showTip) {
                    cell.attr('title', value);
                }
            }
        }

        function setRowUnEditable(record, filed, callBack) {
            var rows = gridEl.find('.' + CLS_GRID_ROW);
            $(rows).each(function (index, element) {
                var obj = $(element).data(ROW_DATA_KEY);
                if (obj == record) {
                    if (filed) {
                        var cell = $(element).find('.grid-body-td-' + filed + ' .' + CLS_EDITABLE);
                        if (cell.size() > 0) {
                            cell.removeClass(CLS_EDITABLE);
                            if (callBack) {
                                var cellContent = cell.find('.' + CLS_CELL_TEXT);
                                cellContent.html(callBack(record[filed]));
                            }
                        }
                    }
                    else {
                        var cell = $(element).find('.' + CLS_GRID_CELL + ' .' + CLS_EDITABLE);
                        if (cell.size() > 0) {
                            cell.removeClass(CLS_EDITABLE);
                            if (callBack) {
                                cell.each(function () {
                                    var cellContent = $(this).find('.' + CLS_CELL_TEXT);
                                    cellContent.html(callBack(cellContent.text()));
                                });
                            }
                        }
                    }

                    return false;
                }
            });
        }

        function setEditable(record, filed, callBack) {
            var rows = gridEl.find('.' + CLS_GRID_ROW);
            $(rows).each(function (index, element) {
                var obj = $(element).data(ROW_DATA_KEY);
                if (obj == record) {
                    if (filed) {
                        var cell = $(element).find('.grid-body-td-' + filed + ' .' + CLS_CELL_INNER);
                        if (cell.size() > 0) {
                            cell.addClass(CLS_EDITABLE);
                            if (callBack) {
                                var cellContent = cell.find('.' + CLS_CELL_TEXT);
                                cellContent.html(callBack(record[filed]));
                            }
                        }
                    }
                }
            });
        }

        function setRowDisable(record) {
            var rows = gridEl.find('.' + CLS_GRID_ROW);
            $(rows).each(function (index, element) {
                var obj = $(element).data(ROW_DATA_KEY);
                if (obj == record) {
                    //先置不可编辑
                    var cell = $(element).find('.' + CLS_GRID_CELL + ' .' + CLS_EDITABLE);
                    if (cell.size() > 0) {
                        cell.removeClass(CLS_EDITABLE);
                    }
                    //改变样式
                    $(element).addClass(CLS_DISABLED);
                    //置checkbox不可用
                    if (_config.rowSelectable != RowSelectableEnum.None) {
                        $(element).find('.' + CLS_CHECKBOX + ' ' + CLS_INPUT_CHECKBOX).attr("disabled", true);
                    }
                    return false;
                }
            });
        }

        function setRowGray(record) {
            var rows = gridEl.find('.' + CLS_GRID_ROW);
            $(rows).each(function (index, element) {
                var obj = $(element).data(ROW_DATA_KEY);
                if (obj == record) {
                    //先置不可编辑
                    var cell = $(element).find('.' + CLS_GRID_CELL + ' .' + CLS_EDITABLE);
                    if (cell.size() > 0) {
                        cell.removeClass(CLS_EDITABLE);
                    }

                    //改变样式
                    $(element).addClass(CLS_DISABLED);

                    return false;
                }
            });
        }

        function setRowUnselected(record) {
            var rows = gridEl.find('.' + CLS_GRID_ROW);
            $(rows).each(function (index, element) {
                var obj = $(element).data(ROW_DATA_KEY);
                if (obj == record) {
                    setSelectRow($(element), false);
                }
            });
        }

        function deleteSelectedRows() {
            var allData = _store.getResults();
            var hasSelection = false;

            $('.' + CLS_GRID_ROW + '.' + CLS_SELECTED, gridEl).each(function (index, element) {
                hasSelection = true;
                var rowData = $(element).data(ROW_DATA_KEY);
                for (var i = 0; i < allData.length; i++) {
                    if (allData[i] == rowData) {
                        allData.splice(i, 1);
                        break;
                    }
                }
                $(element).remove();
            });

            if(hasSelection){
                if(allData.length == 0){
                    createEmptyRow();
                } else {
                    var curRowLength = $('.' + CLS_GRID_ROW).length;
                    if(tbar && curRowLength == 0){
                        tbar.prevPage();
                    }
                }
                setBodyTableHeight();
            }
            
        //            if (hasSelection && allData.length == 0) {
        //                createEmptyRow();
        //            }
        //            
        //            setBodyTableHeight();
        }

        function windowResizeAction() {
            if (masked == true)
                return;
            setBodyTableHeight();
            setHeaderTableWidth();
        }

        function getAutoMaxHeight() {

            var offset = gridViewEl.offset(),
            viewHeight = $(window).height();
            return (viewHeight - offset.top - 10);
        }

        function initBodyEvent() {
            $("." + CLS_GRID_CELL + '.' + CLS_COLUMN_LOOKUP, tableEl[0]).on('click', function (event) {
                if ($(this).hasClass(CLS_COLUMN_LOOKUP)) {
                    if (showedEditor) {
                        showedEditor.hide();
                    }
                    alternateLookupColumnExpand($(this).attr(ATTR_COINDEX));
                    return false;
                }
            });

            if (_config.autoHeight) {
                $([window, document]).resize(windowResizeAction);
            }

            $(tableEl[0]).delegate("." + CLS_GRID_CELL,'click', function (event) {
                if (showedEditor) {
                    showedEditor.hide();
                }
                var $row = $(this).parent("tr");
                if ($row.hasClass(CLS_DISABLED)) {
                    return false;
                }
                onCellClick([event, $row.data(ROW_DATA_KEY)]);
            });
            //点击行
            $(tableEl[0]).delegate("." + CLS_GRID_ROW,'click', function (event) {
                if (showedEditor) {
                    showedEditor.hide();
                }
                if ($(this).hasClass(CLS_DISABLED)) {
                    return false;
                }
                var sender = $(event.target);
                //点击复选框checkBox或复选框所在的单元格
                if (sender.is(CLS_INPUT_CHECKBOX) || sender.find('.' + CLS_CHECKBOX).length > 0 || sender.hasClass(CLS_CHECKBOX)) {
                    var checkBox = sender;
                    if (!sender.is(CLS_INPUT_CHECKBOX)) {
                        var checkBox = sender.find(CLS_INPUT_CHECKBOX);
                        checkBox.click();
                    }
                    setSelectRow($(this), checkBox.attr("checked"));
                } else {
                    var row = $(this);
                    if (_config.rowSelectable == RowSelectableEnum.Single) {
                        setSelectSingleRow(row);
                    } else if (_config.rowSelectable == RowSelectableEnum.Multiple) {
                        var isChecked = row.find(CLS_INPUT_CHECKBOX).attr('checked');
                        setSelectRow(row, !isChecked);
                    } else{
                        setSelectSingleRow(row);
                    }
                    onRowClick([event, row.data(ROW_DATA_KEY)]);
                }
            });

            //移入移出效果
            $(tableEl[0]).delegate('.' + CLS_GRID_ROW, 'mouseover', function () {
                $(this).addClass(CLS_HOVER);
            }).delegate('.' + CLS_GRID_ROW, 'mouseout', function () {
                $(this).removeClass(CLS_HOVER);
            });

            $(tableEl[0]).delegate("." + CLS_GRID_CELL, "mouseover", function () {
                $(this).addClass(CLS_HOVER);
            }).delegate("." + CLS_GRID_CELL, "mouseout", function () {
                $(this).removeClass(CLS_HOVER);
            });

            var showedEditor = null;
            //编辑表格
            $('.' + CLS_BODY_EDITER, tableEl[0]).on('click', function (event) {
                event.stopPropagation();
                if (showedEditor) {
                    showedEditor.hide();
                }
                var cell = $(this).parents('.' + CLS_GRID_CELL),
                colName = cell.attr(ATTR_COLUMN_NAME),
                row = $(this).parents('.' + CLS_GRID_ROW),
                obj = row.data(ROW_DATA_KEY),
                colDef = getCoumnDefinition(colName),
                editor = colDef.editor;
                showedEditor = editor;
                if (obj) {
                    editor.initFiled();
                    editor.show(cell.offset(), cell.width(), function (result) {
                        if (result == 'ok') {
                            var records = [];
                            records.push(obj);
                            if (_config.store) {
                                var dataItems = [];
                                dataItems.push({
                                    key: colName, 
                                    value: editor.getValue()
                                });
                                _config.store.save(records, dataItems);
                            }
                        }
                    }, obj);
                    //在editor.show中会调用beforeShow，而beforeShow中可能会更改editor的结构导致setValue失效，所以放到show的后面
                    editor.setValue(obj[colName], [obj]);
                }

                return false;
            });

            //$('.' + CLS_BODY_EDITER, gridEl[0]).on('click', );

            //滚动条
            gridBodyEl.scroll(function (event) {
                headerEl.scrollLeft($(this).scrollLeft());
            //headerEl.find('.' + CLS_GRID_TABLE).css('left', 0 - $(this).scrollLeft());
            });



        }

        function alternateLookupColumnExpand(colIndex) {
            var selectorindex = '.grid-column-' + colIndex,
            selectorLookup = '[colIndex *="' + colIndex + '-"]';
            var columnEl = $(selectorindex, headerEl);
            if (columnEl.hasClass(CLS_COLUMN_LOOKUP)) {
                var colDef = columnEl.data(DEFINITION_COLUMN);
                if (!columnEl.hasClass(CLS_COLUMN_EXPAND)) {
                    columnEl.addClass(CLS_COLUMN_EXPAND);
                    $(selectorLookup, gridEl).removeClass(CLS_COLUMN_HIDEN);
                    colDef.expanded = true;
                } else {
                    columnEl.removeClass(CLS_COLUMN_EXPAND);
                    $(selectorLookup, gridEl).addClass(CLS_COLUMN_HIDEN);
                    colDef.expanded = false;
                }
                setHeaderTableWidth();
                setBodyTableHeight();

            }
        }

        function isLookupColumnExpand(colIndex) {
            var selectorindex = '.grid-column-' + colIndex,
            columnEl = $(selectorindex, headerEl);
            if (columnEl.hasClass(CLS_COLUMN_LOOKUP)) {
                return columnEl.hasClass(CLS_COLUMN_EXPAND);
            }
            return false;
        }

        function setHeaderSelected(select) {
            headerEl.find('.' + CLS_CHECKBOX + ' ' + CLS_INPUT_CHECKBOX).attr("checked", select);
        }

        function hasSelected(row) {
            return row.hasClass(CLS_SELECTED);
        }

        //选择行
        function setSelectRow(row, select) {
            var changedNum = 0;
            row.each(function (index, element) {
                if (hasSelected($(element)) != select)
                    changedNum++;
            });
            if (select) {
                row.addClass(CLS_SELECTED);

            } else {
                setHeaderSelected(false);
                row.removeClass(CLS_SELECTED);
            }
            row.find(CLS_INPUT_CHECKBOX).attr('checked', select);
            if (changedNum) {
                onRowSelectChanged();
            }
        }
        //仅指定的行被选中，其他行置为不选中
        function setSelectSingleRow(row) {
            $('tr.' + CLS_SELECTED, rowsBodyEl).removeClass(CLS_SELECTED).find(CLS_INPUT_CHECKBOX).attr('checked', false);
            setHeaderSelected(false);
            setSelectRow(row, true);
        }

        //选择全部
        function setAllRrowsSelected() {
            setHeaderSelected(true);

            $('.' + CLS_GRID_ROW, gridEl).each(function () {
                if (!$(this).hasClass(CLS_DISABLED)) {
                    setSelectRow($(this), true);
                }
            });
        }

        function createGroupRow(groupIndex, groupName, element) {
            var cellTempArray = [],
            colspan = getAllColumnsCount();
            if (_config.expandChildren.allowGroupCheck) {
                cellTempArray.push(getCheckColumnCellTemplate());
                colspan -= 1;
            }
            var formater = _config.expandChildren.formater ? _config.expandChildren.formater(groupName, element) : formatters.generalFormatter(groupName);
            cellTempArray.push('<td class="' + CLS_GRID_CELL + '" colSpan="' + colspan + '"><b> ', formater, '</b></td>');
            var groupTemplate = ['<tr rowIndex="', groupIndex, '" class="', CLS_GRID_GROUP_ROW, ' ', CLS_GRID_ROW, '">', cellTempArray.join(''), '</tr>'].join(''),
            rowEl = $(groupTemplate).appendTo(rowsBodyEl);
            rowEl.data(ROW_DATA_KEY, element);
            //var rowEl = createRow(groupIndex,element);
            //rowEl.addClass(CLS_GRID_GROUP_ROW);
            return rowEl;
        }

        function createGroupChildrenRows(groupIndex, childrenDataIndex, parentElement) {
            var children = parentElement[childrenDataIndex];
            $(children).each(function (index, child) {
                var row = createRow(index, child);
                row.addClass(CLS_GRID_GROUP_ROW + '-' + groupIndex);
            });
        }

        function createRow(index, element) {
            var rowTemplate = getRowTemplate(index, element);
            var rowEl = rowTemplate.appendTo(rowsBodyEl);
            $(rowEl[0]).data(ROW_DATA_KEY, element);
            return rowEl;
        }

        // 预处理 显示Data,添加一个不区分大小字的Mapping关系,列配置可以不区分大小写，以下情况例外：
        // 1、如果lookup列绑定的 不是 同一个数据源对象上的数据 这里暂时处理不了
        // 2、带分组的grid,分组要区分大小写,列数据不区分大小写
        function preMappingDataField(obj) {
            if (!_cachedDataFieldMapping) {
                _cachedDataFieldMapping = {};
                for (var objKey in obj) {
                    _cachedDataFieldMapping[objKey.toLowerCase()] = objKey;
                }
            }
        }

        function getCheckColumnCellTemplate() {
            return ['<td align="center" class="checked-column ', CLS_GRID_CELL, '"><div class="', CLS_CELL_INNER, '"><span class="', CLS_CHECKBOX, '"><input type="checkbox" tabindex="0"></span></div></td>'].join('');
        }

        //获取行的模板
        function getRowTemplate(index, obj) {
            var cells = _config.columns, cellTempArray = [],
            rowTemplate;
            if (_config.rowSelectable != RowSelectableEnum.None) {
                cellTempArray.push(getCheckColumnCellTemplate());
            }
            preMappingDataField(obj);

            if(_config.rowNumber){
                rowIndex = index;
                if(tbar){
                    var curPage = tbar.getCurPage(),
                    rowIndex = (curPage-1) * _config.paggingBar.pageSize + index;
                }
                cellTempArray.push('<td class="', CLS_GRID_CELL, ' rownumber">','<div class="', CLS_CELL_INNER, '"><span class="', CLS_CELL_TEXT,'">', rowIndex, '.</span></div></td>');
            }
            $(cells).each(function (colindex, column) {
                var temp;
                if (column.lookup) {
                    var lookuptemplate = getRowLookuptemplate(colindex, obj, column);
                    cellTempArray.push(lookuptemplate);
                    temp = getLookupCellTemplate(colindex);
                } else {
                    var dataField = column.dataIndex ? _cachedDataFieldMapping[column.dataIndex.toLowerCase()] : "";
                    var value = column.formater ? column.formater(column, obj[dataField], obj) : formatters.generalFormatter(obj[dataField]);
                    temp = getCellTemplate(colindex, column, value);
                }
                cellTempArray.push(temp);
            });
            var cellTempObj = $(cellTempArray.join(''));
            cellTempObj.filter("td:first").addClass("first");
            cellTempObj.filter("td:last").addClass("last");

            rowTemplate = $(['<tr rowIndex="', index, '" class="', CLS_GRID_ROW, '">', '<td class="', CLS_GRID_CELL, ' empty">&nbsp;</td></tr>'].join(''));
            rowTemplate.prepend(cellTempObj);
            return rowTemplate;
        }

        function getRowLookuptemplate(index, obj, lookupColumn) {
            var lookup = lookupColumn.lookup,
            lookupobj = lookup.dataIndex ? obj[lookup.dataIndex] : obj,
            result = [];
            $(lookup.columns).each(function (i, column) {
                var value = '';
                if (lookupobj) {
                    var dataField = column.dataIndex ? _cachedDataFieldMapping[column.dataIndex.toLowerCase()] : "";
                    value = column.formater ? column.formater(column, lookupobj[dataField], lookupobj) : formatters.generalFormatter(lookupobj[dataField]);
                }
                var temp = getCellTemplate(index, column, value, i, lookupColumn);
                result.push(temp);
            });
            return result.join('');
        }

        function getLookupCellTemplate(index) {
            var template = ['<td colindex="', index, '" class="', CLS_GRID_CELL, ' ', CLS_COLUMN_LOOKUP, ' grid-column-', index, '"><div class="', CLS_CELL_INNER, ' "></div></td>'].join('');
            return template;
        }

        function getCellTemplate(colIndex, column, value, lookupIndex, lookupColumn) {
            var islookup = (lookupIndex !== undefined),
            type = column.type ? column.type : '',
            editable = column.editor ? CLS_EDITABLE : '',
            width = column.width,
            subWidth = editable ? (width - 34) : width,
            colindexText = islookup ? (colIndex + '-' + lookupIndex) : (colIndex),
            hide = islookup ? (lookupColumn.expanded ? '' : CLS_COLUMN_HIDEN) : (column.hidden ? CLS_COLUMN_HIDEN : ''),
            eitableText = editable ? '<span title="' + TIP_EDIT + '" class="' + CLS_BODY_EDITER + '"></span>' : '',
            showTip = column.showTip ? CLS_GRID_CELL_TIP : '',
            tipText = column.showTip ? 'title="' + value + '"' : '';

            var template = ['<td  class="', CLS_GRID_CELL, ' grid-body-td-', column.dataIndex, ' ', hide, ' ', type, ' grid-column-', colindexText, '" data-column-name="', column.dataIndex, '" colindex="', colindexText, '" style="width:', width, 'px">\
							<div class="', CLS_CELL_INNER, ' ', editable, '" style=" width:', width, 'px"><span class="', CLS_CELL_TEXT, ' ', showTip, '" style="max-width:', subWidth, 'px;text-align:',column.align,';" ', tipText, '>', value, '</span>', eitableText, '</div></td>'].join('');
            return template;
        }

        function setHeaderTableWidth() {
            var bodyTableWidth = tableEl.width(),
            headerWidth = headerEl.width(),
            tEl = headerEl.find('.' + CLS_GRID_TABLE),
            headerTableWidth = tEl.width();

            tEl.css('width', '100%');

            //updated by gaofei for showing HorizonScroll when bodyTable has not data
            if (headerWidth < bodyTableWidth + 30) {
                tEl.css('min-width', bodyTableWidth); //.width();
            }
            else {
                tableEl.width(headerTableWidth);
            }

            if (isHasHorizonScroll(gridBodyEl)) {
                tEl.css('width', Math.max(headerWidth, bodyTableWidth + 30));
            }

            headerEl.scrollLeft(gridBodyEl.scrollLeft());
        }

        function isHasHorizonScroll(element) {
            if (!element.length)
                return false;
            return element[0].scrollWidth > element[0].clientWidth;
        }

        function setBodyTableHeight() {
            if (tableEl.is(':hidden'))
                return;
            var headerHeight = headerEl.height(),
            tableHeight = tableEl.height(),
            setHeight = _config.height ? _config.height : getAutoMaxHeight();
            if (tableHeight < (setHeight - headerHeight)) {
                gridBodyEl.height(tableHeight);
                if (isHasHorizonScroll(gridBodyEl)) {
                    tableHeight += 20;
                    gridBodyEl.height(tableHeight);
                }
            } else {
                gridBodyEl.height(setHeight - headerHeight);
            }
        }

        function initColumns() {
            var editable = false;
            var gf_count = 0;
            for (var i = 0; i < _config.columns.length; i++) {
                var column = _config.columns[i];
                if (column.lookup) {
                    $(column.lookup.columns).each(function (index, element) {
                        element = $.extend(true, {}, _defaultColumnConfig, element);
                        // set default column config
                        column.lookup.columns[index] = element;
                        initColumn(element);
                        if (element.editor) {
                            editable = true;
                        }
                    });
                } else {
                    column = $.extend(true, {}, _defaultColumnConfig, column);
                    // set default column config
                    _config.columns[i] = column;
                    initColumn(column);
                    if (column.editor) {
                        editable = true;
                    }
                }
            }
            if (editable) {
                saveMask = new nsbase.mask(gridEl, {
                    msg: resources.DownLoad_Saving
                });
            }
        }

        function initColumn(column) {
            if (column.editor) {
                // column.editor.initEditor($('body')); 
                // zjk 取消 Editor对dom对象的依赖，生成Editor 移到GridColumn创建的页面
                column.editor.initEditor();
            }
            if (column.type === 'number') {
                if (!column.formater) {
                    column.formater = formatters.numberFormatter(',');
                }
            }
        }



        function createFooter() {
            var info = _config.footer.info || '',
            colspan = getAllColumnsCount(),
            url = _config.footer.url || '#',
            template = ['<td class="grid-footer-cell" colspan="', colspan, '"><a class="grid-footer-link" href = "', url, '">', info, '</a></td>'].join(''),
            el = $(template).appendTo(footerEl);
            if (_config.footer.action) {
                el.children('a').click(_config.footer.action);
            }
        }

        function setGridMultipleEdit(enable) {
            var headerTalbe = headerEl.find('.' + CLS_GRID_TABLE);
            if (enable) {
                expandEditableLookupColumns();
                headerTalbe.addClass(CLS_MULTIPLE_EDIT);
            } else {
                headerTalbe.removeClass(CLS_MULTIPLE_EDIT);
            }
        }

        function expandEditableLookupColumns() {
            $(_config.columns).each(function (i, column) {
                var editable = false;
                if (column.lookup) {
                    $(column.lookup.columns).each(function (index, element) {
                        if (element.editor) {
                            editable = true;
                        }
                    });
                }

                if (editable && !column.expanded) {
                    alternateLookupColumnExpand(i);
                }
            });
        }

        function isMultipleEditStatus() {
            var headerTalbe = headerEl.find('.' + CLS_GRID_TABLE);
            return headerTalbe.hasClass(CLS_MULTIPLE_EDIT);
        }

        //创建表头
        function createHeader() {

            headerEl = $('div.grid-header', gridEl);
            var template = ['<table cellspacing="0" cellpadding="0" class="', CLS_GRID_TABLE, '"><thead><tr class="', CLS_HEADER_ROW, '"></tr></thead></table>'].join('');

            $(template).appendTo(headerEl);
            headerRowEl = headerEl.find('.' + CLS_HEADER_ROW);
            if(_config.rowNumber){
                var rowNumberTmpl = ['<th class="rownumber">\
                                            <div class ="', CLS_HEADER_INNER, '"><div class="', CLS_HEADER_TITLE, '"><span class="icon"></span>#</div></div>\
                                            </div>\
                                        </th>'].join('');
                $(rowNumberTmpl).appendTo(headerRowEl);
            }
            if (_config.rowSelectable != RowSelectableEnum.None) {
                var checkColumnTemplate = ['<th align="center" class="checked-column"><div class="', CLS_HEADER_INNER, '"><span class="', CLS_CHECKBOX, '"><input type="checkbox" tabindex="0"></span></div></th>'].join('');
                $(checkColumnTemplate).appendTo(headerRowEl);
            }

            if (!_config.columns) {
                throw 'not setting columns!';
            }
            for (var i = 0; i < _config.columns.length; i++) {
                var column = _config.columns[i],
                cls = 'grid-column-' + i,
                columnEl = createHeaderColumn(column, i);
                columnEl.addClass(cls);
                columnEl.attr(ATTR_COINDEX, i);
            }

            $('<th class="empty">&nbsp;</th>').appendTo(headerRowEl);
            initHeaderEvent();

            if (_defaultSelectedColumn) {
                selectColumn(_defaultSelectedColumn);
            }

            function createLookupColumns(column, index) {
                if (!column.lookup)
                    return;
                var lookupColumns = column.lookup.columns;
                for (var i = 0; i < lookupColumns.length; i++) {
                    var lookupColumn = lookupColumns[i];
                    createLookupColumn(index, lookupColumn, i, column);
                }
            }

            function createLookupColumn(columnIndex, lookupColumn, lookupIndex, parentColumn) {
                var columnEl = createHeaderColumn(lookupColumn, lookupIndex),
                finalindex = columnIndex + '-' + lookupIndex,
                cls = 'grid-column-' + finalindex;
                columnEl.addClass(cls);
                if (parentColumn && !parentColumn.expanded) {
                    columnEl.addClass(CLS_COLUMN_HIDEN);
                }
                columnEl.attr(ATTR_COINDEX, finalindex);
            }

            function createHeaderColumn(column, index) {
                if (column.lookup) {
                    column.type = CLS_COLUMN_LOOKUP;
                    createLookupColumns(column, index);
                }

                var width = column.width,
                title = column.title || '',
                selectable = (column.selectable || (column.chartTypes && column.chartTypes.length != 0)) ? CLS_HEADER_SELECTABLE : '',
                subtitle = column.subtitle || '',
                type = column.type ? column.type : '',
                display = column.hidden ? 'none' : '',
                headerColumnTemplate = ['<th align="',column.align,'" class="grid-header-column-', column.dataIndex, ' ', selectable, ' ', type, '" style="display: ', display, ';" data-column-name="', column.dataIndex, '">\
												<div class ="', CLS_HEADER_INNER, '"><div class="', CLS_HEADER_TITLE, '" style="text-align:',column.align,';"><span class="icon"></span>', title, 
                                                '<span class="sorted desc"></span></div><div class = "', CLS_HEADER_SUBTITLE, '" style="text-align:',column.align,';">', subtitle, '</div></div>\
												<div class="', CLS_HEADER_EDITER, '"></div></div>\
											</th>'].join(''),
                columnEl = $(headerColumnTemplate).appendTo(headerRowEl),
                innerEl = columnEl.children('.' + CLS_HEADER_INNER);
                bindToolTipItem(columnEl.find("." + CLS_HEADER_TITLE), column);
                if (width && !columnEl.hasClass(CLS_COLUMN_LOOKUP)) {
                    columnEl.width(width);
                    innerEl.width(width);
                }
                if (column.lookup) {
                    columnEl.addClass(CLS_COLUMN_LOOKUP);
                    if (column.expanded) {
                        columnEl.addClass(CLS_COLUMN_EXPAND);
                    }
                    innerEl.empty();
                    var lookupTemplate = '<span class="lookup-arrow"></span>';
                    $(lookupTemplate).appendTo(innerEl);
                }
                columnEl.data(DEFINITION_COLUMN, column);

                if (column.sortable) {
                    columnEl.addClass(CLS_HEADER_SORTABLE);
                }
                if (column.editor && (column.headereditable !== false)) {
                    columnEl.addClass(CLS_EDITABLE);
                    var template = column.editor.getInnerHtml(),
                    containerEl = columnEl.find('.' + CLS_HEADER_EDITER);
                    //containerEl.width(width - 20);
                    var renderElement = $(template).appendTo(containerEl),
                    editType = column.editor.getEitorType(),
                    wrapEl = columnEl.find('.' + CLS_HEADER_EDIT_FIELD_WRAP);
                    wrapEl.width(width - 20);
                    if (editType === 'select') {
                        var defaultSelectTemp = '<option value="" selected="true" >' + TEXT_SELECT_DEFAULT + '</option>';
                        containerEl.find('select').prepend($(defaultSelectTemp));
                    } else if (editType === 'date') {
                        var dateEl = renderElement.find('.grid-edit-filed-date');
                        //dateEl.width(width - 40);qingling
                        dateEl.removeAttr('id');
                        dateEl.removeClass('hasDatepicker');
                    }
                    column.editor.registerEvent(renderElement);
                    var btnTemplate = ['<div class="', CLS_HEADER_EDIT_BTN, '" title="', TIP_SAVE, '"></div>'].join('');
                    //$(btnTemplate).appendTo(columnEl);
                    $(btnTemplate).appendTo(containerEl);
                }
                if (column.selected) {
                    if (_defaultSelectedColumn == null) {
                        _defaultSelectedColumn = columnEl;
                    }
                    else {
                        throw new Error("The default selected column has exist! column dataIndex '" + column.dataIndex + "'");
                    }
                }

                return columnEl;
            }
            function bindToolTipItem(container, dataItem) {//周军zhoujun：如果该列有tooltip这个字段，则为表头添加tooltip
                if (dataItem.tooltip) {
                    var $tooltip = $('<div class="tooltip" resourceKey="notAvailable" ></div>');
                    $tooltip.attr('resourceKey', dataItem.tooltip["key"]);
                    if (dataItem.tooltip["cssClass"]) {
                        $tooltip.addClass(dataItem.tooltip["cssClass"]);
                    }
                    container.append($tooltip);
                }
            }

            function initHeaderEvent() {
                //勾选表头
                headerRowEl.find('.' + CLS_CHECKBOX + ' ' + CLS_INPUT_CHECKBOX).click(function (event) {
                    event.stopPropagation();
                    if ($(this).attr("checked")) {
                        setAllRrowsSelected();
                    } else {
                        clearRrowsSelected();
                    }
                });

                function getEditor(columnEl) {
                    var colDef = columnEl.data(DEFINITION_COLUMN),
                    editor = colDef ? colDef.editor : null;
                    return editor;
                }

                headerEl.find('.' + CLS_HEADER_EDIT_FIELD).focus(function () {
                    var sender = $(this),
                    columnEl = sender.parents('th'),
                    editor = getEditor(columnEl),
                    btn = columnEl.find('.' + CLS_HEADER_EDIT_BTN);
                    if (editor) {
                        editor.clearError(sender);
                        btn.addClass(CLS_VALIDATE);
                    }
                })
                .change(function () {
                    var sender = $(this),
                    columnEl = sender.parents('th'),
                    colValue = sender.val(),
                    editor = getEditor(columnEl);
                    if (editor) {
                        var msg = editor.validateMsg(colValue, _self.getSelections());
                        if (!msg) {
                            editor.clearError(sender);
                        }
                    }
                });

                headerRowEl.find('.' + CLS_COLUMN_LOOKUP).click(function () {
                    var sender = $(this);
                    alternateLookupColumnExpand(sender.attr(ATTR_COINDEX));

                });

                headerRowEl.find('.' + CLS_HEADER_EDIT_BTN).click(function (event) {
                    event.stopPropagation();
                    var sender = $(this),
                    rows = _self.getSelections();
                    if (!rows.length)
                        return;
                    sender.removeClass(CLS_VALIDATE);
                    var columnEl = sender.parents('th').first(),
                    colName = columnEl.attr(ATTR_COLUMN_NAME),
                    colDef = columnEl.data(DEFINITION_COLUMN),
                    filedEl = columnEl.find('.' + CLS_HEADER_EDIT_FIELD),
                    wrapEl = columnEl.find('.' + CLS_HEADER_EDIT_FIELD_WRAP),
                    colValue = '',
                    editor = colDef ? colDef.editor : null;
                    if (editor) {
                        colValue = editor.getValue(wrapEl, filedEl.val());
                        var msg = editor.validateMsg(colValue, rows);
                        if (msg) {
                            editor.setError(msg, filedEl);
                            return;
                        } else {
                            editor.clearError(filedEl);
                            editor.initFiled(wrapEl);
                        }
                        //filedEl.val('');
                        if (_config.store) {
                            var dataItems = [];
                            dataItems.push({
                                key: colName, 
                                value: colValue
                            });
                            _config.store.save(rows, dataItems);
                        }
                    }


                }).hover(function () {
                    $(this).addClass(CLS_HOVER);
                }, function () {
                    $(this).removeClass(CLS_HOVER);
                });

                headerRowEl.find('.' + CLS_HEADER_SUBTITLE).hover(function () {
                    $(this).addClass(CLS_HOVER);
                }, function () {
                    $(this).removeClass(CLS_HOVER);
                });

                headerRowEl.find('th').click(function (event) {
                    if (isMultipleEditStatus())
                        return;
                    var sender = $(this);
                    // target = $(event.target);

                    var defColumn = sender.data(DEFINITION_COLUMN);
                    if (!defColumn)
                        return;
                    var field = defColumn.dataIndex;
                    // zjk 注释掉在subtitle 点击才有排序效果代码
                    if (sender.hasClass(CLS_HEADER_SORTABLE)){ // && target.is('.' + CLS_HEADER_SUBTITLE)) {
                        var sortDirect = SORT_DESC;
                        var sortedEl = sender.find(".sorted");
                        if (sortedEl.hasClass(CLS_SORT_DESC)) {
                            sortDirect = SORT_ASC;
                        }
                        setHeaderSortStyle(sortedEl, sortDirect);
                        if (_store) {
                            if (defColumn) {
                                _store.sort(field, sortDirect);
                            }
                        } else {
                            sortColumn(field, sortDirect);
                        }
                    }
                    if (sender.hasClass(CLS_HEADER_SELECTABLE)) {
                        selectColumn(sender);
                    }
                });

            }
        }

        function selectColumn(columnEl) {
            var headerColumns = headerEl.find("thead > tr > th");
            if (!columnEl.hasClass(CLS_HEADER_SELECTED)) {
                headerColumns.removeClass(CLS_HEADER_SELECTED);
                columnEl.addClass(CLS_HEADER_SELECTED);
                onColumnSelectChanged(columnEl.data(DEFINITION_COLUMN));
            }
        }

        function setHeaderSortStyle(sortedEl, order) {
            // var headerColumns = headerEl.find("thead > tr > th"),
            // cls = CLS_SORT_DESC;
            // if (order == SORT_ASC) {
            //     cls = CLS_SORT_ASC;
            // }
            // headerColumns.removeClass(CLS_SORT_DESC + " " + CLS_SORT_ASC)
            // .removeClass("sorted");
            // columnEl.addClass("sorted " + cls);
            cls = CLS_SORT_DESC;
            if (order == SORT_ASC) {
                cls = CLS_SORT_ASC;
            }
            sortedEl.removeClass(CLS_SORT_DESC).removeClass(CLS_SORT_ASC);
            sortedEl.addClass(cls);
        }

        function sortColumn(field, order) {
            var
            $rows = tableEl.find("tbody > tr"),
            sortDirection = -1;

            if (order == SORT_ASC) {
                sortDirection = 1;
            }
            $rows.sort(function (a, b) {
                var aKey = $(a).data(ROW_DATA_KEY)[field];
                var bKey = $(b).data(ROW_DATA_KEY)[field];
                if (aKey == null) aKey = "";
                if (bKey == null) bKey = "";
                if (aKey < bKey) return -sortDirection;
                if (aKey > bKey) return sortDirection;
                return 0;
            });
            $rows.each(function (i, row) {
                tableEl.find("tbody").append(row);
            });
        }

    //#endregion
    };

    //#region Grid resources 

    Grid.resources = new ResourceManager();
    Grid.resources.addResourcePackage("en-US", {
        Save: "Save",
        ButtonEdit: "Edit",
        General_Select: "Select",
        ShortError_NoData: "NoData",
        DownLoad_Loading: "Loading",
        DownLoad_Saving: "Saving"
    });

    function ResourceManager() {
        var _self = this;
        var _resourcePackages = {}, _currentResourcePackage = null;

        function _init() {
            _self.getResourcePackage = getResourcePackage;
            _self.addResourcePackage = addResourcePackage;
        }

        function addResourcePackage(culture, resourceObj) {
            if (culture == null) {
                throw new Error("The parameter 'culture' cannot be null.");
            }
            var upperCulture = culture.toUpperCase();

            _currentResourcePackage = _resourcePackages[upperCulture] = new ResourcePackage(culture, resourceObj);
        }

        function getResourcePackage() {
            if (_currentResourcePackage === null) {
                _currentResourcePackage = _resourcePackages["EN-US"];
            }
            return _currentResourcePackage;
        }

        _init();
    };
    function ResourcePackage(culture, resourceObj) {
        var _self = this;

        if (culture == null) {
            throw new Error("The parameter 'culture' cannot be null.");
        }
        if (resourceObj == null) {
            throw new Error("The parameter 'resourceObj' cannot be null.");
        }

        _self.Culture = culture;

        if (resourceObj != null) {
            //for (var key in resourceObj) {
            //    if (resourceObj.hasOwnProperty(key) && !_self.hasOwnProperty(key)) {
            //        throw new Error("The key '" + key + "' of grid resource package is not recognized.");
            //    }
            //}
            $.extend(_self, resourceObj);
        }
    }

    //#endregion

    //#region Grid cell formatters
    Grid.cellFormatters = new ValueFormatterManager();
    function ValueFormatterManager() {
        var _self = this;
        var _formatterPackages = {}, _currentF = null;

        function _init() {
            _self.numberFormatter = numberFormatter;
            _self.generalFormatter = generalFormatter;
            _self.extend = extend;
        }

        function extend(formaters) {
            if (typeof (formaters) == "function") {
                var formaterName = getFunctionName(formaters);
                _self[formaterName] = formaters;
            }
            if (typeof (formaters) == "object") {
                $.extend(_self, formaters);
            }
        }

        function getFunctionName(funcBodyString) {
            /// <summary>
            /// Get the name of current invoking function method. NOTE that the current function must be decared as: function _funcName() { }.
            /// If the current function is an anonymous function, the result will be empty string.
            /// </summary>
            /// <param name="funcBodyString">If you know that the function is, you can pass the function body by using: _func_name_.toString().</param>
            /// <returns>The name of current invoking function.</returns>
            var functionNameRegex = /^function\s*?(\w+?)\s*?\(/i;
            if (typeof funcBodyString == "function") {
                funcBodyString = funcBodyString.toString();
            }
            funcBodyString = funcBodyString || arguments.callee.caller.toString();
            var functionNameMatch = funcBodyString.match(functionNameRegex);
            if (functionNameMatch) {
                return functionNameMatch[1];
            }
            else {
                throw new Error("");
            }
        }

        function number(v, format) {
            if (!format) {
                return v;
            }
            v = Number($.isArray(v) || typeof v == 'boolean' || (typeof v == 'string' && $.trim(v).length == 0) ? NaN : v);
            v = isNaN(v) ? NaN : v;
            if (isNaN(v)) {
                return '';
            }
            var comma = ',',
            dec = '.',
            i18n = false,
            neg = v < 0;

            v = Math.abs(v);
            if (format.substr(format.length - 2) == '/i') {
                format = format.substr(0, format.length - 2);
                i18n = true;
                comma = '.';
                dec = ',';
            }

            var hasComma = format.indexOf(comma) != -1,
            psplit = (i18n ? format.replace(/[^\d\,]/g, '') : format.replace(/[^\d\.]/g, '')).split(dec);

            if (2 < psplit.length) {
                throw ('NumberFormatException: invalid format, formats should have no more than 1 period: ' + format);
            }

            if (2 == psplit.length) {
                v = v.toFixed(psplit[1].length);
            } else {
                v = v.toFixed(0);
            }

            var fnum = v.toString();

            psplit = fnum.split('.');

            if (hasComma) {
                var cnum = psplit[0], parr = [], j = cnum.length, m = Math.floor(j / 3), n = cnum.length % 3 || 3;

                for (var i = 0; i < j; i += n) {
                    if (i != 0) {
                        n = 3;
                    }
                    parr[parr.length] = cnum.substr(i, n);
                    m -= 1;
                }
                fnum = parr.join(comma);
                if (psplit[1]) {
                    fnum += dec + psplit[1];
                }
            } else {
                if (psplit[1]) {
                    fnum = psplit[0] + dec + psplit[1];
                }
            }

            return (neg ? '-' : '') + format.replace(/[\d,?\.?]+/, fnum);
        }

        function numberFormatter(format) {
            return function (v) {
                if (!v) v = 0;
                return number(v, format);
            };
        };

        function generalFormatter(v) {
            if (v === undefined || v === null)
                return '';
            var str = v.toString();
            return str.replace(/&/g, '&amp;').replace(/\"/g, '&quot;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
        }

        _init();
    };

    //#endregion

    //#region Get setting

    Grid.setting = new GridSetting();
    function GridSetting() {
        var _self = this;
        function _init() {
            _self.eventEnums = new GridEventEnums();
        }
        _init();
    }
    function GridEventEnums() {
        var _self = this;
        _self.dataReceived = "dataReceived";
        _self.dataError = "dataError";
        _self.rowClick = 'rowClick';
        _self.cellClick = 'cellClick';
        _self.rowSelectChanged = 'rowSelectChanged';
        _self.columnSelectChanged = 'columnSelectChanged';
        _self.afterShow = 'afterShow';
    }

    //#endregion

    //#region Grid editor

    Grid.editor = GridEditor;
    function GridEditor(opt) {
        var resources = GridEditor.resources.getResourcePackage();

        var EditorTypeEnum = {};
        var EditorValueTypeEnum = {};

        var _self = this, editEl, containerEl, btnOK, btnCancel, valueEl, callBackFunc, renderEl, wrapEl, editingRecords, //docEl,
        CLS_DIALOG = 'grid-edit-dialog',
        CLS_BTN_OK = 'grid-edit-btn-ok',
        CLS_BTN_CANCEL = 'grid-edit-btn-cancel',
        CLS_EDIT_FIELD = 'grid-edit-filed',
        CLS_EDIT_FIELD_DATE = 'grid-edit-filed-date',
        CLS_EDIT_FIELD_CHECK = 'grid-edit-filed-check',
        CLS_EDIT_FIELD_WRAP = 'grid-edit-filed-wrap',
        CLS_VALIDATE_ERROR = 'input-validation-error',
        TEXT_REQUIRED = resources.TextRequired,
        NUM_ERROR = resources.NumError,
        TYPE_ERROR = resources.DateError,
        defaults = {
            required: false,
            saveText: resources.Save,
            cancelText: resources.Cancel,
            initField: function (element) {
                if (!element) {
                    element = renderEl;
                }
                element.find('.' + CLS_EDIT_FIELD).val('');
            }
        },
        conf = $.extend(defaults, opt),
        result = {
            OK: 'ok', 
            Cancel: 'cancel'
        };

        _self.initEditor = function (doc) {
            initEditor();
        };
        _self.getEitorType = function () {
            return conf.type;
        };

        _self.getErrorCSS = function () {
            return CLS_VALIDATE_ERROR;
        };

        _self.validateMsg = function (value, reocrds) {

            if (value === undefined || value === null)
                value = _self.getValue();
            if (reocrds === undefined || reocrds === null) {
                reocrds = editingRecords;
            }
            //update by gaofei.
            if (conf.validator) {
                return conf.validator(value, reocrds);
            }

            if (conf.required && $.trim(value.toString()) === '') {
                return TEXT_REQUIRED;
            }

            if (conf.valueType == 'Number' && isNaN(value)) {
                return TYPE_ERROR;
            }
        };

        _self.initFiled = function (renderElement) {
            if (!renderElement) {
                renderElement = renderEl;
            }
            if (conf.initField) {
                conf.initField(renderElement);
            }
        }

        _self.show = function (position, width, callback, obj) {
            _self.clearError();
            //_self.initFiled();
            if (conf.beforeShow) {
                conf.beforeShow(valueEl, obj);
            }
            editEl.show();
            editEl.css(position);
            // zjk 如果单元格宽度超过150 那就在原宽度的基础上加上10
            if (width > 150) editEl.css("width", width + 10);
            callBackFunc = callback;
        };

        _self.isShow = function () {

            return editEl.css('display') != 'none';
        };

        _self.hide = function () {
            editEl.hide();
        };

        _self.getValue = function (renderElement, value) {
            if (!renderElement) {
                renderElement = renderEl;
            }
            if (conf.getValue) {
                return conf.getValue(renderElement);
            }

            if (conf.type == "text-select") {
                return {
                    "select": renderElement.find("select").first().val(), 
                    "text": renderElement.find("input").first().val()
                };
            }

            if (value === undefined || value === null) {
                value = valueEl.val();
            }

            if (conf.format) {
                return conf.format(value);
            }

            return formateValue(value);
        };

        _self.setValue = function (value, records, renderElement) {
            if (!renderElement) {
                renderElement = renderEl;
            }
            if (value === undefined || value === null) {
                value = '';
            }
            if (conf.setValue) {
                conf.setValue(renderElement, value);
            } else {
                valueEl.val(formateValue(value.toString()));
            }
            editingRecords = records;
        };

        _self.getInnerHtml = function () {
            return containerEl.html();
        };

        _self.destroy = function () {
            renderEl.appendTo('body');
            editEl.remove();
            $(document).unbind('click', hideAction);
        };

        _self.setError = function (msg, element) {
            if (!element)
                element = valueEl;
            element.addClass(CLS_VALIDATE_ERROR);
            element.attr('title', msg);
        };

        _self.clearError = function (element) {
            if (!element)
                element = valueEl;
            element.removeClass(CLS_VALIDATE_ERROR);
            element.attr('title', '');
        };

        _self.registerEvent = function (renderElement) {
            if (!renderElement) {
                renderElement = renderEl;
            }
            if (conf.registerEvent) {
                conf.registerEvent(renderElement);
            }
        }

        function initEditor() {
            var template = ['<div class="grid-edit-dialog" style="display: none;">\
				<div class="grid-edit-dialog-inner">\
				</div>\
				<div class="grid-edit-dialog-btn">\
				   <div class="grid-edit-dialog-btn-center">\
					  <a href="#" class="formbtn ', CLS_BTN_OK, '"><span class="formbtn-content">', conf.saveText, '</span></a>\
					  <a href="#" class="formbtn ', CLS_BTN_CANCEL, '"><span class="formbtn-content">', conf.cancelText, '</span></a>\
				  </div>\
				</div>'].join('');
            if (conf.gridId) {
                wrapEl = $('#' + conf.gridId);
            } else {
                wrapEl = $('body');
            }
            editEl = $(template);
            wrapEl.append(editEl);
            containerEl = editEl.find('.grid-edit-dialog-inner');
            btnOK = editEl.find('.' + CLS_BTN_OK);
            btnCancel = editEl.find('.' + CLS_BTN_CANCEL);
            var innerTemplate;
            if (conf.type) {
                switch (conf.type) {
                    case 'text':
                    {
                        innerTemplate = ['<div class="', CLS_EDIT_FIELD_WRAP, '"><input type="text" class="', CLS_EDIT_FIELD, '"/></div>'].join('');
                        break;
                    }
                    case 'select':
                    {
                        conf.required = true;
                        var itemsTemplate = [];

                        $(conf.items).each(function (index, element) {
                            itemsTemplate.push('<option value="' + element.value + '">' + element.text + '</option>');
                        });
                        innerTemplate = ['<div class="', CLS_EDIT_FIELD_WRAP, '"><select class="', CLS_EDIT_FIELD, '">', itemsTemplate.join(''), '</select></div>'].join('');
                        break;
                    }
                    case 'text-select':
                    {
                        var itemsTemplate = [];

                        $(conf.items).each(function (index, element) {
                            itemsTemplate.push('<option value="' + element.value + '">' + element.text + '</option>');
                        });
                        innerTemplate = ['<div class="', CLS_EDIT_FIELD_WRAP, '"><select class="', CLS_EDIT_FIELD, '" style="width:72%;">', itemsTemplate.join(''), '</select><input type="text" class="', CLS_EDIT_FIELD, '" style="margin-left:4px; width:40px;"/></div>'].join('');
                        break;
                    }
                    case 'money':
                    {
                        innerTemplate = ['<div class="', CLS_EDIT_FIELD_WRAP, '"><span>', conf.prefix, '</span><input type="text" class="', CLS_EDIT_FIELD, '"/></div>'].join('');
                        break;
                    }
                    case 'date':
                    {
                        if (conf.hideCheckbox) {
                            innerTemplate = ['<div class="', CLS_EDIT_FIELD_WRAP, '"><input type="text" class="', CLS_EDIT_FIELD, ' ', CLS_EDIT_FIELD_DATE, '" readonly="readonly"/></div>'].join(''); //facebook campaign end date with no checkbox
                        }
                        else {
                            innerTemplate = ['<div class="', CLS_EDIT_FIELD_WRAP, '"><input type="text" class="', CLS_EDIT_FIELD, ' ', CLS_EDIT_FIELD_DATE, '" readonly="readonly"/><input type="checkbox" checked="true" class="', CLS_EDIT_FIELD_CHECK, '"/></div>'].join(''); //7.13-------ql(del**)
                        }
                        conf.exceptHideClass = ['.ui-datepicker', '.ui-datepicker-header'];
                        conf.registerEvent = function (renderElement) {
                            var dateFiledEl = renderElement.find('.' + CLS_EDIT_FIELD_DATE);
                            if (dateFiledEl.datepicker) {
                                dateFiledEl.datepicker({
                                    dateFormat: 'yy/mm/dd', 
                                    changeYear: true, 
                                    changeMonth: true, 
                                    maxDate: new Date(2037, 12 - 1, 30)
                                });
                            }
                            var checkEl = renderElement.find('.' + CLS_EDIT_FIELD_CHECK);
                            checkEl.change(function () {
                                if (!this.checked) {
                                    dateFiledEl.val('2037/12/30');
                                    //dateFiledEl.datepicker("setDate", );
                                    dateFiledEl.attr('disabled', 'disabled');
                                } else {
                                    dateFiledEl.removeAttr('disabled');
                                }
                            });
                        };
                        conf.setValue = function (renderElement, date) {
                            var dateFiledEl = renderElement.find('.' + CLS_EDIT_FIELD_DATE);
                            if (dateFiledEl.datepicker) {
                                var str = dateRenderer(date);
                                dateFiledEl.val(str);
                                var dateTime2037 = Date.parse(new Date("2037/12/30"));
                                if (Date.parse(new Date(str)) >= dateTime2037) {
                                    var checkEl = renderElement.find('.' + CLS_EDIT_FIELD_CHECK);
                                    checkEl.attr('checked', false);
                                    checkEl.change();
                                }
                            //dateFiledEl.datepicker("setDate", str);
                            }
                        };
                        conf.getValue = function (renderElement) {
                            var dateFiledEl = renderElement.find('.' + CLS_EDIT_FIELD_DATE);
                            if (dateFiledEl.datepicker) {
                                var date = dateFiledEl.datepicker("getDate");
                                var dateTime2037 = Date.parse(new Date("2037/12/30"));
                                var dateTime = date.getTime();
                                if (dateTime > dateTime2037) {
                                    return '\/Date(' + dateTime2037 + ')\/';
                                }
                                return '\/Date(' + dateTime + ')\/';
                            }
                        };
                        conf.initField = function (renderElement) {
                            var dateFiledEl = renderElement.find('.' + CLS_EDIT_FIELD_DATE),
                            checkEl = renderElement.find('.' + CLS_EDIT_FIELD_CHECK);
                            dateFiledEl.val('');
                            checkEl.attr('checked', 'checked');
                            checkEl.change();
                        }

                        break;
                    }
                    default:
                    {
                        innerTemplate = '';
                        break;
                    }
                }
            }
            if (innerTemplate) {
                renderEl = $(innerTemplate).appendTo(containerEl);
            } else {
                if (conf.editElementId) {
                    renderEl = $('#' + conf.editElementId).appendTo(containerEl);
                }
            }
            if (conf.registerEvent) {
                conf.registerEvent(renderEl);
            }
            valueEl = containerEl.find('.' + CLS_EDIT_FIELD);
            initEvent();
        }

        function hideAction(event) {
            if (_self.isShow()) {

                var sender = $(event.target),
                dialogCss = '.' + CLS_DIALOG,
                parentWrape = sender.parents(dialogCss),
                hide = !(sender[0] == editEl[0] || parentWrape[0] == editEl[0] || isExceptHideElement(sender));
                if (hide) {
                    _self.hide();
                }
            }
        }

        function isExceptHideElement(element) {
            if (conf.exceptHideClass) {
                var cls = conf.exceptHideClass,
                isExcept = $(element).is(cls);
                if (typeof (cls) == 'string') {
                    isExcept = isExcept || $(element).parents(cls).length > 0;
                } else {
                    var b = false;
                    $(cls).each(function (index, elClass) {
                        isExcept = isExcept || $(element).parents(elClass).length > 0;
                        if (isExcept)
                            return false;
                    });
                }

                return isExcept;
            }
            return false;
        }

        function formateValue(value) {
            if ($.trim(value) === '') {
                return '';
            }
            if (conf.valueType) {
                switch (conf.valueType) {
                    case 'Number':
                        return number(value, '.00');
                    case 'date':
                        return Date(value);
                    case 'boolean':
                        return Boolean(value);
                    default:
                        return value.toString();
                }
            } else {
                return value.toString();
            }
        }

        function initEvent() {
            btnOK.click(function (e) {
                e.stopPropagation();
                e.preventDefault();
                var msg = _self.validateMsg(_self.getValue(), editingRecords);
                if (msg) {
                    _self.setError(msg);
                    return;
                } else {
                    _self.clearError();
                }
                _self.hide();
                if (callBackFunc) {
                    callBackFunc(result.OK);
                }
            });
            btnCancel.click(function (e) {
                e.stopPropagation();
                e.preventDefault();
                _self.clearError();
                _self.hide();
                if (callBackFunc) {
                    callBackFunc(result.Cancel);
                }
            });

            // docEl.click(hideAction);
            $(document).bind('click', hideAction);
        }

        function getClass(object) {
            return Object.prototype.toString.call(object).match(/^\[object\s(.*)\]$/)[1];
        };
        function toDate(dateStr) {
            //The regex to match standard date string, i.e. 2011/12/27
            var standardDateRegex = new RegExp(/^(\d{2}|\d{4})[-,\/]\d{2}[-,\/]\d{2}$/gi);
            //The regex to match mvc style date string, i.e. /Date(1324990982128)/
            var mvcDateRegex = new RegExp(/\/Date\(\d+\)\//gi);
            if (typeof dateStr == "string") {
                if (dateStr.match(_self.standardDateRegex) != null) {
                    return new Date(Date.parse(dateStr));
                }
                else if (dateStr.match(_self.mvcDateRegex) != null) {
                    var ticks = parseInt(dateStr.replace(/\/Date\((\d+)\)\//gim, "$1"));
                    return new Date(ticks);
                }
                else {
                    return new Date(Date.parse(dateStr));
                }
            }
            else if (!getClass(obj) == "Date") {
                return dateStr;
            }
            return new Date(Date.parse(dateStr));
        }
        function dateRenderer(dateStr) {
            var date = dateStr;
            if (!getClass(obj) == "Date") {
                date = toDate(dateStr);
            }
            if (!isNaN(date)) {
                return date.getFullYear() + "/" + padLeft((date.getMonth() + 1), 2, "0") + "/" + padLeft(date.getDate(), 2, "0");
            }
            return dateStr;
        };
    }
    GridEditor.resources = new ResourceManager();
    GridEditor.resources.addResourcePackage("en-US", {
        TextRequired: "The value can not be empty!",
        NumError: "Please input a number!",
        DateError: "Please input correct date!",
        Save: "Save",
        Cancel: "Cancel"
    });

    //#endregion

    nsbase.controls.gridSubTitleUpdater = new function () {
        var me = this;
        me.init = init;
        me.update = update;
        me.reset = reset;

        function init(grid, store) {
            if (store) {
                //store.on("datareceived", function (store, data) {
                //    if (!data) { update(null); return; }
                //    // zjk reconstruct response json result
                //    if (data["ResultSubTitle"] === undefined) {
                //        update(data["sum"][0], grid);
                //    } else {
                //        update(data["ResultSubTitle"], grid);
                //    }
                //});
                store.on(nsbase.controls.store.setting.eventEnums.dataReceived, function (data) {
                    alert(data);
                });
            }
        }

        function update(sumRec, grid) {
            if (sumRec == null) {
                sumRec = {};
            }
            var config = grid.config;
            var columns = config.columns;
            var subTitleItems = [];

            for (var i = 0; i < columns.length; i++) {
                var column = columns[i];
                if (column.subtitle && typeof (column.formater) == "function") {
                    var item = {
                        fieldName: column.dataIndex,
                        formater: column.formater
                    };
                    subTitleItems.push(item);
                }
            }

            $.each(subTitleItems, function (i, item) {
                var fieldName = item.fieldName, formater = item.formater, val = sumRec[fieldName] || 0;
                grid.updateSubTitle(fieldName, formater(val));
            });
        }

        function reset(g, store) {
            init(g, store);
        }
    }();

    //#region Grid pagging bar

    Grid.paggingBar = GridPaggingBar;
    //分页控件
    function GridPaggingBar(config) {
        var resources = GridPaggingBar.resources.getResourcePackage();

        var _self = this, wrapEl, barEl, btnFirst, btnLast, btnNext, btnPre, selectEl, selectListEl, pageContainerEl;
        var CLS_DISABLE = 'disabled';
            

        //start = 0,  //页面的起始记录
        //end = 0,    //页面的结束记录
        //limit = 0,  //限制记录数，一般等同于PageSize
        //totalCount = 0, //记录的总数
        //curPage = 1,    //当前页
        //totalPage = 1;  //总页数
        //var conf = $.extend({
        //    pageSize: 20
        //}, opt);
        //curPage = conf.curPage;
        //totalPage = conf.totalPage;

        var pageBar;
        var _defaultConfig = {
            renderTo: "",
            remote: false,
            pageIndex: 1,
            pageSize: 20,
            store: null
        };
        var _eventObserver = new nsbase.controls.eventObserver(_self);
        var conf, _pageIndex, _pageCount, _store, _localResults;

        /*
        函数功能：析构函数，移除所有注册在Store上的事件，移除页面元素  
        参数：无
        返回值：void
        */
        _self.on = _eventObserver.on;
        _self.un = _eventObserver.un;
        _self.unAll = _eventObserver.unAll;

        /*
            移除pagebar 控件
        
        */
        _self.destroy = function () {
            removeStoreEvents();
            barEl.remove();
        };
        _self.setResults = function (data) {
            _localResults = data;
            var dataCount = _localResults.length;
            if (dataCount % conf.pageSize > 0) {
                _pageCount = parseInt(dataCount / config.pageSize) + 1;
            } else {
                _pageCount = dataCount / conf.pageSize;
            }
            onLoadData();
        }
        
        _self.getCurPage = function () {
            return _pageIndex;
        }
        _self.prevPage = prevPage;
        
        _init();

        //初始化
        function _init() {
            conf = $.extend(true, {}, _defaultConfig, config);
            if (!conf.renderTo) {
                throw 'must privide the element for the bar to render ';
            }

            if (conf.remote && !conf.store) {
                throw new Error("Grid remote pagging must support store config!");
            }

            _pageIndex = conf.pageIndex;
            _store = conf.store;
            wrapEl = $('#' + conf.renderTo);
            if (_store) {
                monitorStoreEvents();

                if (conf.remote) {
                    _store.load({
                        pageIndex: 1
                    });
                } else {
                    _store.load();
                }
            }
           pageBar = new numberPage();
        }

        //上一页 用于自动跳转
        function prevPage(){
            _pageIndex--;
            onLoadData();
        }
       
        //#region moitor Store events

        //监听Store事件
        function monitorStoreEvents() {
            if (_store) {
                _store.on(ns_store.setting.eventEnums.dataBind, storeDataBindAction);
            }
        }

        // 取消监听 Store 事件
        function removeStoreEvents() {
            if (_store) {
                _store.un(ns_store.setting.eventEnums.dataBind, storeDataBindAction);
            }
        }

        function storeDataBindAction(data) {
            var dataCount = _store.getResultsCount();
            if (dataCount % conf.pageSize > 0) {
                _pageCount = parseInt(dataCount / config.pageSize) + 1;
            } else {
                _pageCount = dataCount / conf.pageSize;
            }
            pageBar.syncState();
        }

        //#endregion

        //加载数据
        function onLoadData() {
            if (conf.remote && _store) {
                _store.load({
                    pageIndex: _pageIndex
                });
            } else {
                var pageResults = getLocalPageResults();
                if (_store) {
                    _store.setResults([pageResults]);
                } else {
                    _eventObserver.fireEvent(GridPaggingBar.setting.eventEnums.localDataBind, [pageResults]);
                }
            }

            pageBar.syncState();
        }
        
        function buttonPage () {
            var me = this;
            var PLACEHOLDER_CURRENT_PAGE = "{$curPage}", PLACEHOLDER_TOTAL_PAGE = "{$totalPage}";

            me.syncState = syncState;

            var $pageTpl = $('<div class="bar-btn">\
                                <a href="javascript:void(0);"  class="first">'+ resources.FirstPage + '</a>\
                                <a href="javascript:void(0);" class="prev">'+ resources.PreviousPage +'</a>\
                                <div class="page-number-container"></div>\
                                <a href="javascript:void(0);" class="next">'+ resources.NextPage + '</a>\
                                <a href="javascript:void(0);" class="last">'+ resources.LastPage + '</a>\
                             </div>');
            wrapEl.append($pageTpl);
            var btnFirst = $pageTpl.find("a.first"),
                btnPrev = $pageTpl.find("a.prev"),
                btnNext = $pageTpl.find("a.next"),
                btnLast = $pageTpl.find("a.last"),
                pageNumberContainer = $pageTpl.find(".page-number-container");

            btnFirst.click(function(){
                if($(this).hasClass(CLS_DISABLE)) return false;
                _pageIndex = 1;
                onLoadData();
            });

            btnPrev.click(function(){
                if($(this).hasClass(CLS_DISABLE)) return false;
                _pageIndex --;
                onLoadData();
            });
            btnNext.click(function(){
                if($(this).hasClass(CLS_DISABLE)) return false;
                _pageIndex ++;
                onLoadData();
            });
            btnLast.click(function(){
                if($(this).hasClass(CLS_DISABLE)) return false;
                _pageIndex = _pageCount;
                onLoadData();
            });

            //设置所有按钮状态
            function syncState() {
                if (!_pageCount) {
                    enableButton([btnPrev,btnNext], false);
                    return;
                }
                if (_pageIndex <= _pageCount) {
                    enableButton([btnFirst,btnPrev,btnNext,btnLast], true);
                }

                if (_pageIndex == 1) {
                    enableButton([btnFirst,btnPrev], false);
                }
                if (_pageIndex == _pageCount || _pageCount === 0) {
                    enableButton([btnNext, btnLast], false);
                }
                setPageNotice();
            }
            

            function setPageNotice () {
                if (_pageCount > 0) {
                    var pagingtext = resources.PagingText.replace(PLACEHOLDER_TOTAL_PAGE, _pageCount).replace(PLACEHOLDER_CURRENT_PAGE, _pageIndex);
                    pageNumberContainer.text(pagingtext);
                }
            }

        }

        function numberPage () {
            var me = this;


             me.syncState = syncState;

            var numberHolder = "{$number}",selectedHolder = "{$selected}",
                ALL_SHOW_LIMIT_COUNT = 5, RANGE_SHOW_LIMIT_COUNT = 2;
            var $pageTpl = $('<div class="bar-btn">\
                                <a href="javascript:void(0);" class="prev">&nbsp;</a>\
                                <div class="page-number-container"></div>\
                                <a href="javascript:void(0);" class="next">&nbsp;</a>\
                             </div>');
            var numberPageTpl = '<a class="page-number '+ selectedHolder +'" href="javascript:void(0);">'+ numberHolder +'</a>'
            var btnPrev = $pageTpl.find("a.prev"),
                btnNext = $pageTpl.find("a.next"),
                pageNumberContainer = $pageTpl.find(".page-number-container");

            
            wrapEl.append($pageTpl);
            wrapEl.delegate('.page-number', 'click', function (event) {
                event.preventDefault();
                var sender = $(this);
                if(sender.hasClass("selected")) return false;
                _pageIndex = parseInt(sender.text());
                onLoadData();
            });

            btnPrev.click(function(){
                if($(this).hasClass(CLS_DISABLE)) return false;
                _pageIndex --;
                onLoadData();
            });
            btnNext.click(function(){
                if($(this).hasClass(CLS_DISABLE)) return false;
                _pageIndex ++;
                onLoadData();
            });

            function getNumberPages () {
                var pageItems = [];
                if(_pageCount == 1){
                    addPageItem(1,1);
                    return pageItems.join('');
                }

                if (_pageCount <= ALL_SHOW_LIMIT_COUNT) {//show all pages number
                    curMax = _pageCount;
                    addPageItem(1, _pageCount);
                } else {//show begin with 1
                    var startNum = (_pageIndex <= ALL_SHOW_LIMIT_COUNT) ? 1 : (_pageIndex - RANGE_SHOW_LIMIT_COUNT),
                    lastLimit = _pageIndex + RANGE_SHOW_LIMIT_COUNT,
                    endNum = lastLimit < _pageCount ? (lastLimit > ALL_SHOW_LIMIT_COUNT ? lastLimit : ALL_SHOW_LIMIT_COUNT) : _pageCount;
                    if (startNum > 1) {
                        addPageItem(1, 1);
                        addEllipsis();
                    }
                    curMax = endNum;
                    addPageItem(startNum, endNum);
                }
                if (curMax < _pageCount) {
                    addEllipsis();
                    addPageItem(_pageCount, _pageCount);
                }
                
                function addPageItem (from,to) {
                    for (var i = from; i <= to; i++) {
                        var template;
                        if(i===_pageIndex){
                            template = numberPageTpl.replace(numberHolder,i).replace(selectedHolder,"selected");
                        } else {
                            template = numberPageTpl.replace(numberHolder,i).replace(selectedHolder,"");
                        }
                        pageItems.push(template);
                    }
                }

                function addEllipsis() {
                    var template = '<em class="number-ellipsis">...</em>';
                    pageItems.push(template);
                }

                return pageItems.join('');
            }

            function syncState () {
                pageNumberContainer.empty();
                var numberpage = getNumberPages();
                pageNumberContainer.append(numberpage);

                enableButton([btnPrev,btnNext],true);
                if(_pageIndex==1){
                   enableButton([btnPrev],false);
                }
                if(_pageIndex == _pageCount || _pageCount === 0){
                    enableButton([btnNext],false);
                }
            }
        }

        function enableButton(buttons, enable) {
            $.each(buttons,function(index,$button){
                if(enable){
                    $button.removeClass(CLS_DISABLE);
                } else{
                    $button.addClass(CLS_DISABLE);
                }
            });
        }
        

        function getLocalPageResults() {
            var pageResults = null;
            if (_store) {
                _localResults = _localResults || _store.getResults();
            }

            if (_localResults) {
                var startIndex = (_pageIndex - 1) * conf.pageSize;
                var endIndex = startIndex + conf.pageSize;
                pageResults = _localResults.slice(startIndex, endIndex);
            }
            return pageResults;
        }

        //设置分页链接
        function setLinkHerf(button) {
            var params = {
                start: 0, 
                limit: conf.pageSize
            };
            if (button.hasClass(CLS_LAST)) {
                params.start = (totalPage - 1) * conf.pageSize;

            }
            if (button.hasClass(CLS_NEXT)) {
                params.start = curPage * conf.pageSize;
            }
            if (button.hasClass(CLS_PREV)) {
                params.start = (curPage - 1) * conf.pageSize;
            }

            var pathname = window.location.pathname;
            button.attr('href', pathname + '?' + $.param(params));
        }

    };
    GridPaggingBar.resources = new ResourceManager();
    GridPaggingBar.resources.addResourcePackage("en-US", {
        FirstPage:'第一页',
        LastPage:'最后一页',
        PreviousPage: "上一页",
        NextPage: "下一页",
        PagingText: "当前页 {$curPage}/{$totalPage} 总页数"
    });

    GridPaggingBar.setting = new GridPaggingBarSetting();
    function GridPaggingBarSetting() {
        var _self = this;
        function _init() {
            _self.eventEnums = new GridPaggingBarEventEnums();
        }
        _init();
    }
    function GridPaggingBarEventEnums() {
        var _self = this;
        _self.localDataBind = "localDataBind";
    }
//#endregion

})(jQuery);